package websocket

import (
	"math/rand"
	"time"

	"github.com/zeromicro/go-zero/core/logx"
)

// 开始游戏
func (r *GameRoom) StartGame() {
	r.gameMu.Lock()
	defer r.gameMu.Unlock()

	if r.GameState == nil {
		r.GameState = &GameState{
			Status:  "waiting",
			Snakes:  make(map[string]*Snake),
			Foods:   []SnakeSegment{},
			Scores:  make(map[string]int),
			Ready:   make(map[string]bool),
			Players: make(map[string]*PlayerInfo),
		}
	}

	if r.GameState.Status == "playing" {
		logx.Infof("[GameRoom.StartGame] 游戏已经在运行中，房间ID: %s", r.ID)
		return
	}

	// 初始化游戏状态
	r.GameState.Status = "playing"
	r.GameState.StartTime = time.Now().Unix()

	// 初始化所有玩家
	r.mu.RLock()
	clients := make([]*Client, 0, len(r.Clients))
	for _, client := range r.Clients {
		clients = append(clients, client)
	}
	r.mu.RUnlock()

	// 初始化蛇和分数
	colors := []string{"#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF", "#00FFFF"}
	for i, client := range clients {
		color := colors[i%len(colors)]
		// 为每个玩家分配不同的起始位置
		x, y := getRandomStartPosition(len(clients), i)
		r.GameState.Snakes[client.UserID] = &Snake{
			Segments: []SnakeSegment{
				{x, y},
				{x - 1, y},
				{x - 2, y},
			},
			Direction: "right",
			Color:     color,
		}
		r.GameState.Scores[client.UserID] = 0
		r.GameState.Ready[client.UserID] = true
		r.GameState.Players[client.UserID] = &PlayerInfo{
			UserID:   client.UserID,
			UserName: client.UserName,
			Score:    0,
			Color:    color,
		}
	}

	// 生成初始食物
	r.generateFood(5)

	logx.Infof("[GameRoom.StartGame] 游戏开始，房间ID: %s, 玩家数量: %d", r.ID, len(clients))

	// 广播游戏开始消息
	startMsg := Message{
		Type:    int(MessageTypeGameStart),
		Content: "游戏开始！",
		Time:    time.Now().Unix(),
	}
	r.Broadcast(startMsg)

	// 开始游戏循环
	if r.gameLoopTicker != nil {
		r.gameLoopTicker.Stop()
	}
	r.gameLoopTicker = time.NewTicker(200 * time.Millisecond)
	go r.gameLoop()
}

// 停止游戏
func (r *GameRoom) StopGame() {
	r.gameMu.Lock()
	defer r.gameMu.Unlock()

	if r.GameState == nil {
		return
	}

	if r.GameState.Status != "playing" {
		return
	}

	// 停止游戏循环
	if r.gameLoopTicker != nil {
		r.gameLoopTicker.Stop()
		r.gameLoopTicker = nil
	}

	// 更新游戏状态
	r.GameState.Status = "ended"
	r.GameState.EndTime = time.Now().Unix()

	logx.Infof("[GameRoom.StopGame] 游戏结束，房间ID: %s", r.ID)

	// 广播游戏结束消息
	endMsg := Message{
		Type:    int(MessageTypeGameEnd),
		Content: "游戏结束！",
		Time:    time.Now().Unix(),
	}
	r.Broadcast(endMsg)

	// 广播最终游戏状态
	r.BroadcastGameState()
}

// 游戏循环
func (r *GameRoom) gameLoop() {
	for {
		select {
		case <-r.gameLoopTicker.C:
			// 检查游戏是否仍在运行
			r.gameMu.RLock()
			status := r.GameState.Status
			r.gameMu.RUnlock()

			if status != "playing" {
				return
			}

			// 更新游戏状态
			r.updateGameState()

			// 广播游戏状态
			r.BroadcastGameState()

			// 检查游戏是否应该结束
			if r.shouldGameEnd() {
				r.StopGame()
				return
			}
		}
	}
}

// 更新游戏状态
func (r *GameRoom) updateGameState() {
	r.gameMu.Lock()
	defer r.gameMu.Unlock()

	// 移动所有蛇
	for userID, snake := range r.GameState.Snakes {
		// 获取蛇头
		head := snake.Segments[0]

		// 根据方向计算新的蛇头位置
		newHead := head
		switch snake.Direction {
		case "up":
			newHead.Y--
		case "down":
			newHead.Y++
		case "left":
			newHead.X--
		case "right":
			newHead.X++
		}

		// 检查是否撞墙或撞自己
		if r.isCollision(newHead, snake, userID) {
			// 蛇死亡，移除该玩家
			delete(r.GameState.Snakes, userID)
			// 更新玩家状态
			if player, exists := r.GameState.Players[userID]; exists {
				player.Alive = false
			}
			continue
		}

		// 检查是否吃到食物
		ateFood := false
		newFoods := []SnakeSegment{}
		for _, food := range r.GameState.Foods {
			if newHead.X == food.X && newHead.Y == food.Y {
				ateFood = true
				// 增加分数
				r.GameState.Scores[userID] += 10
				// 更新玩家分数
				if player, exists := r.GameState.Players[userID]; exists {
					player.Score = r.GameState.Scores[userID]
				}
			} else {
				newFoods = append(newFoods, food)
			}
		}

		// 更新食物列表
		r.GameState.Foods = newFoods

		// 如果吃到食物，生成新的食物
		if ateFood {
			r.generateFood(1)
		} else {
			// 否则移除尾部
			snake.Segments = snake.Segments[:len(snake.Segments)-1]
		}

		// 添加新的头部
		snake.Segments = append([]SnakeSegment{newHead}, snake.Segments...)
	}
}

// 检查碰撞
func (r *GameRoom) isCollision(head SnakeSegment, snake *Snake, userID string) bool {
	// 检查边界
	if head.X < 0 || head.X >= 40 || head.Y < 0 || head.Y >= 40 {
		return true
	}

	// 检查是否撞到自己
	for i := 1; i < len(snake.Segments); i++ {
		if head.X == snake.Segments[i].X && head.Y == snake.Segments[i].Y {
			return true
		}
	}

	// 检查是否撞到其他蛇
	for otherUserID, otherSnake := range r.GameState.Snakes {
		if otherUserID == userID {
			continue
		}
		for _, segment := range otherSnake.Segments {
			if head.X == segment.X && head.Y == segment.Y {
				return true
			}
		}
	}

	return false
}

// 检查游戏是否应该结束
func (r *GameRoom) shouldGameEnd() bool {
	r.gameMu.RLock()
	defer r.gameMu.RUnlock()

	// 计算存活的玩家数量
	aliveCount := 0
	for _, _ = range r.GameState.Snakes {
		aliveCount++
	}

	// 如果只剩一个或没有玩家，游戏结束
	return aliveCount <= 1
}

// 生成食物
func (r *GameRoom) generateFood(count int) {
	for i := 0; i < count; i++ {
		// 生成随机位置
		x := rand.Intn(40)
		y := rand.Intn(40)

		// 检查是否与蛇身重叠
		valid := true
		for _, snake := range r.GameState.Snakes {
			for _, segment := range snake.Segments {
				if x == segment.X && y == segment.Y {
					valid = false
					break
				}
			}
			if !valid {
				break
			}
		}

		// 如果位置有效，添加食物
		if valid {
			r.GameState.Foods = append(r.GameState.Foods, SnakeSegment{X: x, Y: y})
		} else {
			// 重试
			i--
		}
	}
}

// 处理游戏操作
func (r *GameRoom) handleGameOp(userID string, op GameOp) {
	r.gameMu.Lock()
	defer r.gameMu.Unlock()

	if r.GameState == nil || r.GameState.Status != "playing" {
		return
	}

	// 根据操作类型处理
	if op.Op == "direction" && op.Dir != "" {
		// 更新蛇的方向
		if snake, exists := r.GameState.Snakes[userID]; exists {
			// 防止180度转向
			if (snake.Direction == "up" && op.Dir != "down") ||
			   (snake.Direction == "down" && op.Dir != "up") ||
			   (snake.Direction == "left" && op.Dir != "right") ||
			   (snake.Direction == "right" && op.Dir != "left") {
				snake.Direction = op.Dir
			}
		}
	} else if op.Op == "ready" && op.Ready != nil {
		// 更新准备状态
		r.mu.Lock()
		r.Ready[userID] = *op.Ready
		r.mu.Unlock()
	}
}

// 获取随机起始位置
func getRandomStartPosition(totalPlayers, index int) (int, int) {
	// 根据玩家数量和索引分配不同的起始位置
	switch totalPlayers {
	case 1:
		return 20, 20
	case 2:
		if index == 0 {
			return 10, 20
		} else {
			return 30, 20
		}
	case 3:
		if index == 0 {
			return 10, 10
		} else if index == 1 {
			return 30, 10
		} else {
			return 20, 30
		}
	default:
		// 4人或更多
		positions := [][2]int{
			{10, 10}, {30, 10}, {10, 30}, {30, 30},
		}
		return positions[index%4][0], positions[index%4][1]
	}
}
